home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / warp / term.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  17.8 KB  |  815 lines

  1. /* $Header: term.c,v 7.0.1.2 86/12/12 17:04:09 lwall Exp $ */
  2.  
  3. /* $Log:    term.c,v $
  4.  * Revision 7.0.1.2  86/12/12  17:04:09  lwall
  5.  * Baseline for net release.
  6.  * 
  7.  * Revision 7.0.1.1  86/10/16  10:53:20  lwall
  8.  * Added Damage.  Fixed random bugs.
  9.  * 
  10.  * Revision 7.0  86/10/08  15:14:02  lwall
  11.  * Split into separate files.  Added amoebas and pirates.
  12.  * 
  13.  */
  14.  
  15. #include "EXTERN.h"
  16. #include "warp.h"
  17. #include "bang.h"
  18. #include "intrp.h"
  19. #include "object.h"
  20. #include "play.h"
  21. #include "score.h"
  22. #include "sig.h"
  23. #include "us.h"
  24. #include "util.h"
  25. #include "weapon.h"
  26. #include "INTERN.h"
  27. #include "term.h"
  28.  
  29. int typeahead = FALSE;
  30.  
  31. char tcarea[TCSIZE];    /* area for "compiled" termcap strings */
  32.  
  33. /* guarantee capability pointer != Nullch */
  34. /* (I believe terminfo will ignore the &tmpaddr argument.) */
  35.  
  36. #define Tgetstr(key) ((tstr = tgetstr(key,&tmpaddr)) ? tstr : nullstr)
  37.  
  38. #ifdef PUSHBACK
  39. struct keymap {
  40.     char km_type[128];
  41.     union km_union {
  42.     struct keymap *km_km;
  43.     char *km_str;
  44.     } km_ptr[128];
  45. };
  46.  
  47. #define KM_NOTHIN 0
  48. #define KM_STRING 1
  49. #define KM_KEYMAP 2
  50. #define KM_BOGUS 3
  51.  
  52. #define KM_TMASK 3
  53. #define KM_GSHIFT 4
  54. #define KM_GMASK 7
  55.  
  56. typedef struct keymap KEYMAP;
  57.  
  58. KEYMAP *topmap INIT(Null(KEYMAP*));
  59.  
  60. void mac_init();
  61. KEYMAP *newkeymap();
  62. void pushstring();
  63. #endif
  64.  
  65. /* terminal initialization */
  66.  
  67. void
  68. term_init()
  69. {
  70.     savetty();                /* remember current tty state */
  71.  
  72. #ifdef TERMIO
  73.     ospeed = _tty.c_cflag & CBAUD;    /* for tputs() */
  74.     ERASECH = _tty.c_cc[VERASE];    /* for finish_command() */
  75.     KILLCH = _tty.c_cc[VKILL];        /* for finish_command() */
  76. #else
  77.     ospeed = _tty.sg_ospeed;        /* for tputs() */
  78.     ERASECH = _tty.sg_erase;        /* for finish_command() */
  79.     KILLCH = _tty.sg_kill;        /* for finish_command() */
  80. #endif
  81.  
  82.     /* The following could be a table but I can't be sure that there isn't */
  83.     /* some degree of sparsity out there in the world. */
  84.  
  85.     switch (ospeed) {            /* 1 second of padding */
  86. #ifdef BEXTA
  87.         case BEXTA:  just_a_sec = 1920; break;
  88. #else
  89. #ifdef B19200
  90.         case B19200: just_a_sec = 1920; break;
  91. #endif
  92. #endif
  93.         case B9600:  just_a_sec =  960; break;
  94.         case B4800:  just_a_sec =  480; break;
  95.         case B2400:  just_a_sec =  240; break;
  96.         case B1800:  just_a_sec =  180; break;
  97.         case B1200:  just_a_sec =  120; break;
  98.         case B600:   just_a_sec =   60; break;
  99.     case B300:   just_a_sec =   30; break;
  100.     /* do I really have to type the rest of this??? */
  101.         case B200:   just_a_sec =   20; break;
  102.         case B150:   just_a_sec =   15; break;
  103.         case B134:   just_a_sec =   13; break;
  104.         case B110:   just_a_sec =   11; break;
  105.         case B75:    just_a_sec =    8; break;
  106.         case B50:    just_a_sec =    5; break;
  107.         default:     just_a_sec =  960; break;
  108.                     /* if we are running detached I */
  109.     }                    /*  don't want to know about it! */
  110. }
  111.  
  112. /* set terminal characteristics */
  113.  
  114. void
  115. term_set(tcbuf)
  116. char *tcbuf;        /* temp area for "uncompiled" termcap entry */
  117. {
  118.     char *tmpaddr;            /* must not be register */
  119.     Reg1 char *tstr;
  120.     char *tgetstr();
  121.     char *s;
  122.     int retval;
  123.  
  124. #ifdef PENDING
  125. #ifndef FIONREAD
  126. #ifndef RDCHK
  127.     /* do no delay reads on something that always gets closed on exit */
  128.  
  129.     devtty = open("/dev/tty",0);
  130.     if (devtty < 0) {
  131.     printf(cantopen,"/dev/tty");
  132.     finalize(1);
  133.     }
  134.     fcntl(devtty,F_SETFL,O_NDELAY);
  135. #endif
  136. #endif
  137. #endif
  138.     
  139.     /* get all that good termcap stuff */
  140.  
  141.     retval = tgetent(tcbuf,getenv("TERM"));    /* get termcap entry */
  142.     if (retval < 1) {
  143. #ifdef VERBOSE
  144.     printf("No termcap %s found.\n", retval ? "file" : "entry");
  145. #else
  146.     fputs("Termcap botch\n",stdout);
  147. #endif
  148.     finalize(1);
  149.     }
  150.     tmpaddr = tcarea;            /* set up strange tgetstr pointer */
  151.     s = Tgetstr("pc");            /* get pad character */
  152.     PC = *s;                /* get it where tputs wants it */
  153.     if (!tgetflag("bs")) {        /* is backspace not used? */
  154.     BC = Tgetstr("bc");        /* find out what is */
  155.     if (BC == nullstr)         /* terminfo grok's 'bs' but not 'bc' */
  156.         BC = Tgetstr("le");
  157.     } else
  158.     BC = "\b";            /* make a backspace handy */
  159.     UP = Tgetstr("up");            /* move up a line */
  160.     ND = Tgetstr("nd");            /* non-destructive move cursor right */
  161.     DO = Tgetstr("do");            /* move cursor down */
  162.     if (!*DO)
  163.     DO = Tgetstr("nl");
  164.     CL = Tgetstr("cl");            /* get clear string */
  165.     CE = Tgetstr("ce");            /* clear to end of line string */
  166.     CM = Tgetstr("cm");            /* cursor motion - PWP */
  167.     HO = Tgetstr("ho");            /* home cursor if no CM - PWP */
  168.     CD = Tgetstr("cd");            /* clear to end of display - PWP */
  169.     SO = Tgetstr("so");            /* begin standout */
  170.     SE = Tgetstr("se");            /* end standout */
  171.     if ((SG = tgetnum("sg"))<0)
  172.     SG = 0;                /* blanks left by SG, SE */
  173.     US = Tgetstr("us");            /* start underline */
  174.     UE = Tgetstr("ue");            /* end underline */
  175.     if ((UG = tgetnum("ug"))<0)
  176.     UG = 0;                /* blanks left by US, UE */
  177.     if (*US)
  178.     UC = nullstr;            /* UC must not be NULL */
  179.     else
  180.     UC = Tgetstr("uc");        /* underline a character */
  181.     if (!*US && !*UC) {            /* no underline mode? */
  182.     US = SO;            /* substitute standout mode */
  183.     UE = SE;
  184.     UG = SG;
  185.     }
  186.     LINES = tgetnum("li");        /* lines per page */
  187.     COLS = tgetnum("co");        /* columns on page */
  188.     AM = tgetflag("am");        /* terminal wraps automatically? */
  189.     XN = tgetflag("xn");        /* then eats next newline? */
  190.     VB = Tgetstr("vb");
  191.     if (!*VB)
  192.     VB = "\007";
  193.     CR = Tgetstr("cr");
  194.     if (!*CR) {
  195.     if (tgetflag("nc") && *UP) {
  196.         CR = safemalloc((MEM_SIZE)strlen(UP)+2);
  197.         Sprintf(CR,"%s\r",UP);
  198.     }
  199.     else
  200.         CR = "\r";
  201.     }
  202.     if (LINES <= 0)
  203.     LINES = 24;
  204.     if (COLS <= 0)
  205.     COLS = 80;
  206.  
  207.     BCsize = comp_tc(bsptr,BC,1);
  208.     BC = bsptr;
  209.  
  210.     if (!*ND)                /* not defined? */
  211.     NDsize = 1000;            /* force cursor addressing */
  212.     else {
  213.     NDsize = comp_tc(cmbuffer,ND,1);
  214.     myND = malloc((unsigned)NDsize);
  215.     movc3(NDsize,cmbuffer,myND);
  216.     if (debugging) {
  217.         int scr;
  218.  
  219.         printf("ND");
  220.         for (scr=0; scr<NDsize; scr++)
  221.         printf(" %d",myND[scr]);
  222.         printf("\n");
  223.     }
  224.     }
  225.  
  226.     if (!*UP)                /* not defined? */
  227.     UPsize = 1000;            /* force cursor addressing */
  228.     else {
  229.     UPsize = comp_tc(cmbuffer,UP,1);
  230.     myUP = malloc((unsigned)UPsize);
  231.     movc3(UPsize,cmbuffer,myUP);
  232.     if (debugging) {
  233.         int scr;
  234.  
  235.         printf("UP");
  236.         for (scr=0; scr<UPsize; scr++)
  237.         printf(" %d",myUP[scr]);
  238.         printf("\n");
  239.     }
  240.     }
  241.  
  242.     if (!*DO) {                /* not defined? */
  243.     myDO = DO = "\n";        /* assume a newline */
  244.     DOsize = 1;
  245.     }
  246.     else {
  247.     DOsize = comp_tc(cmbuffer,DO,1);
  248.     myDO = malloc((unsigned)DOsize);
  249.     movc3(DOsize,cmbuffer,myDO);
  250.     if (debugging) {
  251.         int scr;
  252.  
  253.         printf("DO");
  254.         for (scr=0; scr<DOsize; scr++)
  255.         printf(" %d",myDO[scr]);
  256.         printf("\n");
  257.     }
  258.     }
  259.     if (debugging)
  260.     Fgets(cmbuffer,(sizeof cmbuffer),stdin);
  261.  
  262.     CMsize = comp_tc(cmbuffer,tgoto(CM,20,20),0);
  263.     if (PC != '\0') {
  264.     char *p;
  265.  
  266.     for (p=filler+(sizeof filler)-1;!*p;--p)
  267.         *p = PC;
  268.     }
  269.     charsperhalfsec = ospeed >= B9600 ? 480 :
  270.               ospeed == B4800 ? 240 :
  271.               ospeed == B2400 ? 120 :
  272.               ospeed == B1200 ? 60 :
  273.               ospeed == B600 ? 30 :
  274.           /* speed is 300 (?) */   15;
  275.  
  276.     gfillen = ospeed >= B9600 ? (sizeof filler) :
  277.           ospeed == B4800 ? 13 :
  278.           ospeed == B2400 ? 7 :
  279.           ospeed == B1200 ? 4 :
  280.                 1+BCsize;
  281.     if (ospeed < B2400)
  282.     lowspeed = TRUE;
  283.  
  284.     strcpy(term,ttyname(2));
  285.  
  286.     if (!*CM || !BCsize)
  287.     no_can_do("dumb");
  288.     if (!scorespec && (LINES < 24 || COLS < 80))
  289.     no_can_do("puny");
  290.  
  291.     crmode();
  292.     raw();
  293.     noecho();                /* turn off echo */
  294.     nonl();
  295.  
  296. #ifdef PUSHBACK
  297.     mac_init(tcbuf);
  298. #endif
  299. }
  300.  
  301. #ifdef PUSHBACK
  302. void
  303. mac_init(tcbuf)
  304. char *tcbuf;
  305. {
  306.     char tmpbuf[1024];
  307.  
  308.     tmpfp = fopen(filexp(getval("WARPMACRO",WARPMACRO)),"r");
  309.     if (tmpfp != Nullfp) {
  310.     while (fgets(tcbuf,1024,tmpfp) != Nullch) {
  311.         mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
  312.     }
  313.     Fclose(tmpfp);
  314.     }
  315. }
  316.  
  317. void
  318. mac_line(line,tmpbuf,tbsize)
  319. char *line;
  320. char *tmpbuf;
  321. int tbsize;
  322. {
  323.     Reg1 char *s;
  324.     Reg2 char *m;
  325.     Reg3 KEYMAP *curmap;
  326.     Reg4 int ch;
  327.     Reg5 int garbage = 0;
  328.     static char override[] = "\r\nkeymap overrides string\r\n";
  329.  
  330.     if (topmap == Null(KEYMAP*))
  331.     topmap = newkeymap();
  332.     if (*line == '#' || *line == '\n')
  333.     return;
  334.     if (line[ch = strlen(line)-1] == '\n')
  335.     line[ch] = '\0';
  336.     m = dointerp(tmpbuf,tbsize,line," \t");
  337.     if (!*m)
  338.     return;
  339.     while (*m == ' ' || *m == '\t') m++;
  340.     for (s=tmpbuf,curmap=topmap; *s; s++) {
  341.     ch = *s & 0177;
  342.     if (s[1] == '+' && isdigit(s[2])) {
  343.         s += 2;
  344.         garbage = (*s & KM_GMASK) << KM_GSHIFT;
  345.     }
  346.     else
  347.         garbage = 0;
  348.     if (s[1]) {
  349.         if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
  350.         puts(override);
  351.         free(curmap->km_ptr[ch].km_str);
  352.         curmap->km_ptr[ch].km_str = Nullch;
  353.         }
  354.         curmap->km_type[ch] = KM_KEYMAP + garbage;
  355.         if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
  356.         curmap->km_ptr[ch].km_km = newkeymap();
  357.         curmap = curmap->km_ptr[ch].km_km;
  358.     }
  359.     else {
  360.         if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
  361.         puts(override);
  362.         else {
  363.         curmap->km_type[ch] = KM_STRING + garbage;
  364.         curmap->km_ptr[ch].km_str = savestr(m);
  365.         }
  366.     }
  367.     }
  368. }
  369.  
  370. KEYMAP*
  371. newkeymap()
  372. {
  373.     Reg1 int i;
  374.     Reg2 KEYMAP *map;
  375.  
  376. #ifndef lint
  377.     map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
  378. #else
  379.     map = Null(KEYMAP*);
  380. #endif /* lint */
  381.     for (i=127; i>=0; --i) {
  382.     map->km_ptr[i].km_km = Null(KEYMAP*);
  383.     map->km_type[i] = KM_NOTHIN;
  384.     }
  385.     return map;
  386. }
  387.  
  388. #endif
  389.  
  390. /* print out a file, stopping at form feeds */
  391.  
  392. void
  393. page(filename,num)
  394. char *filename;
  395. bool num;
  396. {
  397.     int linenum = 1;
  398.  
  399.     tmpfp = fopen(filename,"r");
  400.     if (tmpfp != NULL) {
  401.     while (fgets(spbuf,(sizeof spbuf),tmpfp) != NULL) {
  402.         if (*spbuf == '\f') {
  403.         printf("[Type anything to continue] ");
  404.         Fflush(stdout);
  405.         getcmd(spbuf);
  406.         printf("\r\n");
  407.         if (*spbuf == INTRCH)
  408.             finalize(0);
  409.         if (*spbuf == 'q' || *spbuf == 'Q')
  410.             break;
  411.         }
  412.         else {
  413.         if (num)
  414.             printf("%3d   %s\r",linenum++,spbuf);
  415.         else
  416.             printf("%s\r",spbuf);
  417.         }
  418.     }
  419.     Fclose(tmpfp);
  420.     }
  421. }
  422.  
  423. void
  424. move(y, x, chadd)
  425. int y, x;
  426. int chadd;
  427. {
  428.     Reg1 int ydist;
  429.     Reg2 int xdist;
  430.     Reg3 int i;
  431.     Reg4 char *s;
  432.  
  433.     ydist = y - real_y;
  434.     xdist = x - real_x;
  435.     i = ydist * (ydist < 0 ? -UPsize : DOsize) +
  436.         xdist * (xdist < 0 ? -BCsize : NDsize);
  437.     beg_qwrite();
  438.     if (i <= CMsize) {
  439.     if (ydist < 0)
  440.         for (; ydist; ydist++)
  441.         for (i=UPsize,s=myUP; i; i--)
  442.             qaddch(*s++);
  443.     else
  444.         for (; ydist; ydist--)
  445.         for (i=DOsize,s=myDO; i; i--)
  446.             qaddch(*s++);
  447.     if (xdist < 0)
  448.         for (; xdist; xdist++)
  449.         for (i=BCsize,s=BC; i; i--)
  450.             qaddch(*s++);
  451.     else
  452.         for (; xdist; xdist--)
  453.         for (i=NDsize,s=myND; i; i--)
  454.             qaddch(*s++);
  455.     }
  456.     else {
  457.     tputs(tgoto(CM,x,y),0,cmstore);
  458.     }
  459.     real_y = y;
  460.     real_x = x;
  461.     if (chadd) {
  462.     qaddch(chadd);
  463.     }
  464.     if (maxcmstring != cmbuffer)
  465.     end_qwrite();
  466. }
  467.  
  468. void
  469. do_tc(s,l)
  470. char *s;
  471. int l;
  472. {
  473.     beg_qwrite();
  474.     tputs(s,l,cmstore);
  475.     end_qwrite();
  476. }
  477.  
  478. int
  479. comp_tc(dest,s,l)
  480. char *dest;
  481. char *s;
  482. int l;
  483. {
  484.     maxcmstring = dest;
  485.     tputs(s,l,cmstore);
  486.     return(maxcmstring-dest);
  487. }
  488.  
  489. void
  490. helper()
  491. {
  492.     clear();
  493.     mvaddstr(0,4,"h or 4          left");
  494.     mvaddstr(1,4,"j or 2          down                Use with SHIFT to fire torpedoes.");
  495.     mvaddstr(2,4,"k or 8          up                  Use with CTRL or FUNCT to fire");
  496.     mvaddstr(3,4,"l or 6          right                   phasers or turbolasers.");
  497.     mvaddstr(4,4,"b or 1          down and left       Use preceded by 'a' or 'r' for");
  498.     mvaddstr(5,4,"n or 3          down and right          attractors or repulsors.");
  499.     mvaddstr(6,4,"y or 7          up and left         Use normally for E or B motion.");
  500.     mvaddstr(7,4,"u or 9          up and right");
  501.     mvaddstr(8,4,"");
  502.     mvaddstr(9,4,"del or %        fire photon torpedoes in every (reasonable) direction.");
  503.     mvaddstr(10,4,"s               stop all torpedoes.");
  504.     mvaddstr(11,4,"S or 0          stop the Enterprise when in warp mode.");
  505.     mvaddstr(12,4,"d/D             destruct all torpedoes/current vessel.");
  506.     mvaddstr(13,4,"i/w             switch to Enterprise & put into impulse/warp mode.");
  507.     mvaddstr(14,4,"c/v             switch to Enterprise & make cloaked/visible.");
  508.     mvaddstr(15,4,"p               switch to Base.");
  509.     mvaddstr(16,4,"o               toggle to other vessel (from E to B, or vice versa.)");
  510.     mvaddstr(17,4,"z               zap (suppress) blasts near Enterprise next cycle");
  511.     mvaddstr(18,4,"");
  512.     mvaddstr(19,4,"^R      refresh the screen.              ^Z      suspend the game.");
  513.     mvaddstr(20,4,"q       exit this round (if you haven't typed q within 10 cycles).");
  514.     mvaddstr(21,4,"Q       exit this game.");
  515.     mvaddstr(22,4,"");
  516.     mvaddstr(23,4,"                   [Hit space to continue]");
  517.     Fflush(stdout);
  518.     do {
  519.     getcmd(spbuf);
  520.     } while (*spbuf != ' ');
  521.     rewrite();
  522.     
  523. }
  524.  
  525. void
  526. rewrite()
  527. {
  528.     Reg1 int x;
  529.     Reg2 int y;
  530.     Reg3 OBJECT *obj;
  531.  
  532.     clear();
  533.     for (y=0; y<YSIZE; y++) {
  534.     for (x=0; x<XSIZE; x++) {
  535.         if (numamoebas && amb[y][x] != ' ')
  536.         mvaddc(y+1,x*2,amb[y][x]);
  537.         if (obj=occupant[y][x]) {
  538.         if (obj->image != ' ')
  539.             mvaddc(y+1,x*2,obj->image);
  540.         }
  541.     }
  542.     }
  543.     Sprintf(spbuf,
  544.     "%-4s E: %4d %2d B: %5d %3d Enemies: %-3d Stars: %-3d Stardate%5d.%1d %9ld",
  545.     "   ", 0, 0, 0, 0, 0, 0, timer/10+smarts*100, timer%10, 0L);
  546.     mvaddstr(0,0,spbuf);
  547.     oldeenergy = oldbenergy = oldcurscore =
  548.     oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1;
  549.                     /* force everything to fill in */
  550.     if (damage)
  551.     olddamage = 0;
  552.     if (!ent)
  553.     etorp = 0;
  554.     if (!base)
  555.     btorp = 0;
  556.     display_status();
  557. }
  558.  
  559. char
  560. cmstore(ch)
  561. Reg1 char ch;
  562. {
  563.     *maxcmstring++ = ch;
  564. }
  565.  
  566. /* discard any characters typed ahead */
  567.  
  568. void
  569. eat_typeahead()
  570. {
  571. #ifdef PUSHBACK
  572.     if (!typeahead && nextin==nextout)    /* cancel only keyboard stuff */
  573. #else
  574.     if (!typeahead)
  575. #endif
  576.     {
  577. #ifdef PENDING
  578.     while (input_pending())
  579.         Read_tty(buf,sizeof(buf));
  580. #else /* this is probably v7, with no rdchk() */
  581.     ioctl(_tty_ch,TIOCSETP,&_tty);
  582. #endif
  583.     }
  584. }
  585.  
  586. void
  587. settle_down()
  588. {
  589.     dingaling();
  590.     Fflush(stdout);
  591.     sleep(1);
  592. #ifdef PUSHBACK
  593.     nextout = nextin;            /* empty circlebuf */
  594. #endif
  595.     eat_typeahead();
  596. }
  597.  
  598. #ifdef PUSHBACK
  599. /* read a character from the terminal, with multi-character pushback */
  600.  
  601. int
  602. read_tty(addr,size)
  603. char *addr;
  604. int size;    /* ignored for now */
  605. {
  606. #ifdef lint
  607.     size = size;
  608. #endif
  609.     if (nextout != nextin) {
  610.     *addr = circlebuf[nextout++];
  611.     nextout %= PUSHSIZE;
  612.     return 1;
  613.     }
  614.     else {
  615.     size = read(0,addr,1);
  616.     if (size < 0)
  617.         sig_catcher(SIGHUP);
  618.     if (metakey) {
  619.         if (*addr & 0200) {
  620.         pushchar(*addr & 0177);
  621.         *addr = '\001';
  622.         }
  623.     }
  624.     else
  625.         *addr &= 0177;
  626.     return 1;
  627.     }
  628. }
  629.  
  630. #ifdef PENDING
  631. #ifndef FIONREAD
  632. #ifndef RDCHK
  633. int
  634. circfill()
  635. {
  636.     Reg1 int howmany;
  637.     Reg2 int i;
  638.  
  639.     assert (nextin == nextout);
  640.     howmany = read(devtty,circlebuf+nextin,metakey?1:PUSHSIZE-nextin);
  641.     if (howmany > 0) {
  642.     if (metakey) {
  643.         if (circlebuf[nextin] & 0200) {
  644.         circlebuf[nextin] &= 0177;
  645.         pushchar('\001');
  646.         }
  647.     }
  648.     else
  649.         for (i = howmany+nextin-1; i >= nextin; i--)
  650.         circlebuf[i] &= 0177;
  651.     nextin += howmany;
  652.     nextin %= PUSHSIZE;    /* may end up 1 if metakey */
  653.     }
  654.     return howmany;
  655. }
  656. #endif /* RDCHK */
  657. #endif /* FIONREAD */
  658. #endif /* PENDING */
  659.  
  660. void
  661. pushchar(ch)
  662. char ch;
  663. {
  664.     nextout--;
  665.     if (nextout < 0)
  666.     nextout = PUSHSIZE - 1;
  667.     if (nextout == nextin) {
  668.     fputs("\r\npushback buffer overflow\r\n",stdout);
  669.     sig_catcher(0);
  670.     }
  671.     circlebuf[nextout] = ch;
  672. }
  673.  
  674. #else /* PUSHBACK */
  675. #ifndef read_tty
  676. /* read a character from the terminal, with hacks for O_NDELAY reads */
  677.  
  678. int
  679. read_tty(addr,size)
  680. char *addr;
  681. int size;
  682. {
  683.     if (is_input) {
  684.     *addr = pending_ch;
  685.     is_input = FALSE;
  686.     return 1;
  687.     }
  688.     else {
  689.     size = read(0,addr,size);
  690.     if (size < 0)
  691.         sig_catcher(SIGHUP);
  692.     if (metakey) {
  693.         if (*addr & 0200) {
  694.         pending_ch = *addr & 0177;
  695.         is_input = TRUE;
  696.         *addr = '\001';
  697.         }
  698.     }
  699.     else
  700.         *addr &= 0177;
  701.     return size;
  702.     }
  703. }
  704. #endif /* read_tty */
  705. #endif /* PUSHBACK */
  706.  
  707. int
  708. read_nd(buff, siz)
  709. char *buff;
  710. int siz;
  711. {
  712.     if (!input_pending())
  713.     return 0;
  714.  
  715.     getcmd(buff);
  716.     return 1;
  717. }
  718.  
  719. /* get a character into a buffer */
  720.  
  721. void
  722. getcmd(whatbuf)
  723. Reg3 char *whatbuf;
  724. {
  725. #ifdef PUSHBACK
  726.     Reg1 KEYMAP *curmap;
  727.     Reg2 int i;
  728.     bool no_macros; 
  729.     int times = 0;            /* loop detector */
  730.     char scrchar;
  731.  
  732. tryagain:
  733.     curmap = topmap;
  734. /*    no_macros = (whatbuf != buf && nextin == nextout);  */
  735.     no_macros = FALSE;
  736. #endif
  737.     for (;;) {
  738.     errno = 0;
  739.     if (read_tty(whatbuf,1) < 0 && !errno)
  740.         errno = EINTR;
  741. #ifdef read_tty
  742.     if (metakey) {
  743.         if (*whatbuf & 0200) {
  744.         *what_buf &= 037;    /* punt and hope they don't notice */
  745.         }
  746.     }
  747.     else
  748.         *whatbuf &= 0177;
  749. #endif /* read_tty */
  750.     if (errno && errno != EINTR) {
  751.         perror(readerr);
  752.         sig_catcher(0);
  753.     }
  754. #ifdef PUSHBACK
  755.     if (*whatbuf & 0200 || no_macros) {
  756.         *whatbuf &= 0177;
  757.         goto got_canonical;
  758.     }
  759.     if (curmap == Null(KEYMAP*))
  760.         goto got_canonical;
  761.     for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
  762.         Read_tty(&scrchar,1);
  763.     }
  764.     switch (curmap->km_type[*whatbuf] & KM_TMASK) {
  765.     case KM_NOTHIN:            /* no entry? */
  766.         if (curmap == topmap)    /* unmapped canonical */
  767.         goto got_canonical;
  768.         settle_down();
  769.         goto tryagain;
  770.     case KM_KEYMAP:            /* another keymap? */
  771.         curmap = curmap->km_ptr[*whatbuf].km_km;
  772.         assert(curmap != Null(KEYMAP*));
  773.         break;
  774.     case KM_STRING:            /* a string? */
  775.         pushstring(curmap->km_ptr[*whatbuf].km_str);
  776.         if (++times > 20) {        /* loop? */
  777.         fputs("\r\nmacro loop?\r\n",stdout);
  778.         settle_down();
  779.         }
  780.         no_macros = FALSE;
  781.         goto tryagain;
  782.     }
  783. #else
  784.     *whatbuf &= 0177;
  785.     break;
  786. #endif
  787.     }
  788.  
  789. got_canonical:
  790. #ifndef TERMIO
  791.     if (*whatbuf == '\r')
  792.     *whatbuf = '\n';
  793. #endif
  794.     if (whatbuf == buf)
  795.     whatbuf[1] = FINISHCMD;        /* tell finish_command to work */
  796. }
  797.  
  798. #ifdef PUSHBACK
  799. void
  800. pushstring(str)
  801. char *str;
  802. {
  803.     Reg1 int i;
  804.     char tmpbuf[PUSHSIZE];
  805.     Reg2 char *s = tmpbuf;
  806.  
  807.     assert(str != Nullch);
  808.     interp(s,PUSHSIZE,str);
  809.     for (i = strlen(s)-1; i >= 0; --i) {
  810.     s[i] ^= 0200; 
  811.     pushchar(s[i]);
  812.     }
  813. }
  814. #endif
  815.